# -*- mode: python; coding: utf-8; -*-
##--------------------------------------------------------------------------##
##
## Copyright (C) 1998-2003 Markus Oberhumer <markus@oberhumer.com>
## Copyright (C) 2003 Mt. Hood Playing Card Co.
## Copyright (C) 2005-2010 Skomoroh <skomoroh@users.sourceforge.net>
## Copyright (C) 2010-2013 Jeremy Austin-Bardo <tjaustinbardo@gmail.com>
##
## This program is free software: you can redistribute it and/or modify
## it under the terms of the GNU General Public License as published by
## the Free Software Foundation, either version 3 of the License.
##
## This program is distributed in the hope that it will be useful,
## but WITHOUT ANY WARRANTY; without even the implied warranty of
## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
## GNU General Public License for more details.
##
## You should have received a copy of the GNU General Public License
## along with this program.  If not, see <http://www.gnu.org/licenses/>.
##
##--------------------------------------------------------------------------##
__docformat__ = "restructuredtext en"

from .. import autostacks
from .. import comparecards as cmp_cards
from .. import pilelib as stack
from .. import stackfill as fill
from ..forms import acesup as AcesUpLayout
from ..gamelib import info as gi, state, game
from ..packlib import info  as cs
from ..piles import (spider as SpiderStack, pairing as PairingStack,
                     freecell as FreeCellStack, talon as TalonStack)
from ..utillib.misc import kwdefault

Wrap = stack.StackWrapper
GT, SL = gi.GT, gi.SL


class AcesUp_Foundation(stack.AbstractFoundation):

    def cardsBuild(self, from_stack, cards):
        """
        cardsBuild(from_stack, cards) -> bool

        Check whether base card is lower than top card and parent method.

        :Parameters:
          from_stack : pysollib.stack.Stack
            pile from which cards playing.

          cards : tuple of ..pilelib.card.Card
            current card seq playing to pile.

        :return: pile can build with cards from played from_stack?

        seealso::
          `pysollib.stackcaps.builds` for the *capability* check.
        """
        if not super(AcesUp_Foundation, self).cardsBuild(from_stack, cards):
            return False
        c0 = cards[0]
        for c1 in (p.TOPCARD for p in self.game.s['rows']
                                if p.cards and p is not from_stack):
            if (cmp_cards.isSameSuit([c0, c1]) and
                c1['rank'] > c0['rank'] or c1['rank'] == cs.ACE):
                return c0['rank'] != cs.ACE
        return False


class AcesUp_RowStack(stack.BasicRowStack):

    def cardsBuild(self, from_stack, cards):
        """
        cardsBuild(from_stack, cards) -> bool

        Check whether pile is gap and parent method.

        :Parameters:
          from_stack : pysollib.stack.Stack
            pile from which cards playing.

          cards : tuple of ..pilelib.card.Card
            current card seq playing to pile.

        :return: pile can build with cards from played from_stack?

        seealso::
          `pysollib.stackcaps.builds` for the *capability* check.
        """

        if not super(AcesUp_RowStack, self).cardsBuild(from_stack, cards):
            return False
        return not self.cards

    def clickHandler(self, event):
        return self.doubleclickHandler(event)


class PerpetualMotion_Foundation(stack.AbstractFoundation):

    def __init__(self, x, y, game, **cap):
        """
        __init__(x, y, game[, max_accept=4, min_accept=4]) -> None

        :Parameters:
          x : int
            left x-coordinate.

          y : int
            top y-coordinate.

          game : pysollib.game.Game
            current Game.

        seealso::
          `pysollib.stackcaps` with details of *capability* keywords.
        """
        kwdefault(cap, min_accept=4, max_accept=4)
        super(PerpetualMotion_Foundation, self).__init__(x, y, game, **cap)

    def cardsBuild(self, from_stack, cards):
        """
        cardsBuild(from_stack, cards) -> bool

        Check whether base card is lower than top card and parent method.

        :Parameters:
          from_stack : pysollib.stack.Stack
            pile from which cards playing.

          cards : tuple of ..pilelib.card.Card
            current card seq playing to pile.

        :return: pile can build with cards from played from_stack?

        seealso::
          `pysollib.stackcaps.builds` for the *capability* check.
        """
        return (super(PerpetualMotion_Foundation, self).cardsBuild(from_stack,
                       cards) and cmp_cards.isSameRank(cards))


class PerpetualMotion_RowStack(stack.RK_RowStack):

    def __init__(self, x, y, game, **cap):
        """
        __init__(x, y, game[, dir=0, base_rank=GAP]) -> None

        :Parameters:
          x : int
            left x-coordinate.
          y : int
            top y-coordinate.
          game : pysollib.game.Game
            current Game.

        seealso::
          `pysollib.stackcaps` with details of *capability* keywords.
        """
        kwdefault(cap, dir=0, base_rank=cs.GAP)
        super(PerpetualMotion_RowStack, self).__init__(x, y, game, **cap)

    def cardsDrop(self, stacks, event=None):
        """
        cardsDrop(stacks) -> tuple

        Drop SEQUENCE that builds on `game.s.foundations[0]` or parent method.

        :Parameters:
          stacks : tuple of pysollib.stack.Stacks
            piles to check if SEQUENCE builds.

        :return: tuple of pile to drop SEQUENCE and SEQUENCE len.
        """
        pile, foundations = self.SEQUENCE, self.game.s.foundations
        if stacks is foundations:
            if foundations[0].cardsBuild(self, pile):
                return (foundations[0], len(pile))
            else:
                return (None, 0)
        return super(PerpetualMotion_RowStack, self).cardsDrop(stacks)


class AcesUp(game.Game):
    """
    Drop 1 deck by low card of same suit pair on foundation except high ace
    using 4 top row and no reserve and dealing all row.

    :CVariables:
      _layout_ : pysollib.layout.Layout
        .. pysollib.layouts.acesup.AcesUpLayout
        - row [4 horz N, vert offset]
        - talon [1 NW, no offset]
        - foundation [1 NE, no offset]

      _talon_ : pysollib.stack.Stack
        .. pysollib.stack.DealRowTalon
        Deal 1 card per row. No redeal.

      _foundation_ : pysollib.stack.Stack
        .. AcesUp_Foundation (max_cards=48)

      _row_ : pysollib.stack.Stack
        .. AcesUp_RowStock
        Init 1 card per. Build any top when gap. Play top with ace high. Drop
        low rank of same suit pair on foundation.

      _hint_ : pysollib.hint.AbstractHint
        .. pysollib.hint.defaultHint

    :note:
      ⟪autodrop⟫ disabled for non-events.
    """
    __info__ = dict(id=0x3ad07, name='Aces Up', game_type=(GT.PAIRING |
                    GT.CHILDREN | GT.POPULAR | GT.KDE | GT.XPAT), decks=1,
                    skill_level=SL.LUCK, altnames=('Aces High', 'Drivel',),
                    version='3.00')
    __author__ = 'Markus Oberhumer'
    __version__ = 7.70

    _layout_ = AcesUpLayout.AcesUpLayout
    _talon_ = stack.DealRowTalon
    _foundation_ = Wrap(AcesUp_Foundation, max_cards=48)
    _row_ = AcesUp_RowStack

    def _create_game(self, **kw):
        """
        Create game format.

        Augment pile placements based on current form and group attributes.

        .. \_create_game(rows=4, playcards=12, texts=True, bases=[ANY])
             -> Layout
        """
        kwdefault(kw, rows=4, playcards=12, texts=True, bases=[cs.ANY])
        return super(AcesUp, self)._create_game(**kw)

    def _start(self, **kw):
        """
        _start() -> None

        Deal 1 card per row.
        """
        self._play_sound('deal')
        self.s['talon'].dealRow()

    @property
    def is_complete(self):
        """
        :returns: whether foundation is full and row has 4 ace.
        :requires: `pysollib.comparecards.isSameRank` for comparing ranks
        """
        s = self.s
        if not s['foundations'][0].is_filled:
            return False
        rows = [p.TOPCARD['rank'] for p in s['rows'] if len(p.cards) == 1]
        return len(rows) == 4 and cmp_cards.isSameRank(rows, rank=cs.ACE)

    def _autopiles(self, event=None):
        """
        Return piles for auto or quick move.

        Overide to disable autodrop when not event.

        .. \_autopiles(self, event=None) -> seq(seq(Pile ...), seq(Pile ...),
             seq(Pile ...))
        """
        piles = super(AcesUp, self)._autopiles(event)
        if event is None:
            return autostacks.auto_flip_quickplay(piles)
        return piles


class AcesUp5(AcesUp):
    """
    Drop 1 deck by low card of same suit pair on foundation except high ace
    using 5 top row and no reserve, dealing all row.

    :CVariables:
      _layout_ : pysollib.layout.Layout
        .. pysollib.layouts.acesup.AcesUpLayout
        - row [5 horz N, vert offset]
        - talon [1 NW, no offset]
        - foundation [1 NE, no offset]

      _talon_ : pysollib.stack.Stack
        .. pysollib.stack.DealRowTalon
        Deal 1 card per row. No redeals.

      _foundation_ : pysollib.stack.Stack
        .. AcesUp_Foundation (max_cards=48)

      _row_ : pysollib.stack.Stack
        .. AcesUp_RowStock
        Init 1 card per. Build any top when gap. Play top with ace high. Drop
        low rank of same suit pair on foundation.

      _hint_ : pysollib.hint.AbstractHint
        .. pysollib.hint.defaultHint

    :note:
      ⟪autodrop⟫ disabled for non-events.
    """
    __info__ = dict(id=0x3aae1, name='Aces Up 5', game_type=GT.PAIRING,
                    decks=1, skill_level=SL.LUCK, version='0.90fc',
                    altnames=('Aces Up (5 Piles)',))
    __author__ = 'Skomoroh'
    __version__ = 7.70

    def _create_game(self, **kw):
        """
        Create game format.

        Augment pile placements based on current form and group attributes.

        .. \_create_game(rows=5, playcards=12, texts=True, bases=[ANY])
             -> Layout
        """
        kw.setdefault('rows', 5)
        return super(AcesUp5, self)._create_game(**kw)


class Fortunes(AcesUp):
    """
    Drop 1 deck by low card of same suit pair on foundation except high
    ace using 4 any row and no reserve, dealing all RowStack.

    :CVariables:
      _layout_ : pysollib.layout.Layout
        .. pysollib.layouts.acesup.AcesUpLayout
        - row [4 horz N, vert offset]
        - talon [1 NW, no offset]
        - foundation [1 NE, no offset]

      _talon_ : pysollib.stack.Stack
        .. pysollib.stack.DealRowTalon
        Deal 1 card per row. No redeals.

      _foundation_ : pysollib.stack.Stack
        .. AcesUp_Foundation (max_cards=48)

      _row_ : pysollib.stack.Stack
        .. AcesUp_RowStock (max_move=MAX, max_accept=MAX)
        Init 1 card per. Build any sequence when gap. Play sequence with ace
        high. Drop low rank of same suit pair on foundation.

      _hint_ : pysollib.hint.AbstractHint
        .. pysollib.hint.defaultHint

    :note:
      ⟪autodrop⟫ disabled for non-events.
    """
    __info__ = dict(id=0x3aa4e, name='Fortunes', game_type=(GT.PAIRING |
                    GT.GNOME), decks=1, skill_level=SL.LUCK, version='4.60')
    __author__ = 'Markus Oberhumer'
    __version__ = 7.70

    _row_ = Wrap(AcesUp_RowStack, max_move=cs.MAX, max_accept=cs.MAX)


class RussianAces(AcesUp):
    """
    Drop 1 deck by low card of same suit pair on foundation except high
    ace using 4 top row and no reserve, dealing gap row.

    :CVariables:
      _layout_ : pysollib.layout.Layout
        .. pysollib.layouts.acesup.AcesUpLayout
        - row [4 horz N, vert offset]
        - talon [1 NW, no offset]
        - foundation [1 NE, no offset]

      _talon_ : pysollib.stack.Stack
        .. pysollib.talon.DealGapRowTalon
        Deal 1 card per row gap else all. No redeals.

      _foundation_ : pysollib.stack.Stack
        .. AcesUp_Foundation (max_cards=48)

      _row_ : pysollib.stack.Stack
        .. AcesUp_RowStock
        Init 1 card per. Build any top when gap. Play top with ace high. Drop
        low rank of same suit pair on foundation.

      _hint_ : pysollib.hint.AbstractHint
        .. pysollib.hint.defaultHint

    :note:
      ⟪autodrop⟫ disabled for non-events.
    """
    __info__ = dict(id=0x3aa55, name='Russian Aces', game_type=GT.PAIRING,
                    decks=1, skill_level=SL.LUCK, version='3.00')
    __author__ = 'Markus Oberhumer'
    __version__ = 7.70

    _talon_ = TalonStack.DealGapRowTalon


class FiringSquad(AcesUp):
    """
    Drop 1 deck by low card of same suit pair on foundation except high
    ace using 4 top row and 1 reserve, dealing all row.

    :CVariables:
      _layout_ : pysollib.layout.Layout
        .. pysollib.layouts.acesup.AcesUpLayout
        - row [4 horz N, vert offset]
        - talon [1 NW, no offset]
        - reserve [1 S s.talon, no offset]
        - foundation [1 NE, no offset]

      _talon_ : pysollib.stack.Stack
        .. pysollib.stack.DealRowTalon
        Deal 1 card per row. No redeals.

      _foundation_ : pysollib.stack.Stack
        .. AcesUp_Foundation (max_cards=48)

      _row_ : pysollib.stack.Stack
        .. AcesUp_RowStock
        Init 1 card per. Build any top when gap. Play top with ace high. Drop
        low rank of same suit pair on foundation.

      _reserve_ : pysollib.stack.Stack
        .. pysollib.stack.ReserveStack
        Build any top. Play top. Max 1 card.

      _hint_ : pysollib.hint.AbstractHint
        .. pysollib.hint.defaultHint

    :note:
      ⟪autodrop⟫ disabled for non-events.
    """
    __info__ = dict(id=0x3abc7, name='Firing Squad', game_type=GT.PAIRING,
                    decks=1, skill_level=SL.BALANCED, version='0.93fc')
    __author__ = 'Skomoroh'
    __version__ = 7.70

    _reserve_ = stack.ReserveStack


class PerpetualMotion(game.Game):
    """
    Drop 1 deck by full same rank sequence on foundation using 4 top row,
    dealing all row with infinite redeals.

    :CVariables:
      _layout_ : pysollib.layout.Layout
        .. pysollib.layouts.acesup.AcesUpLayout
        - row [4 horz N, vert offset]
        - talon [1 NW, no offset]
        - foundation [1 NE, no offset]

      _talon_ : pysollib.stack.Stack
        .. pysollib.stack.DealRowRedealTalon (max_rounds=INFINITE)
        Deal 1 card per row. Infinite redeals.

      _foundation_ : pysollib.stack.Stack
        .. pysollib.stacks.pairing.SetRK_SingleFoundation

      _row_ : pysollib.stack.Stack
        .. pysollib.stacks.pairing.SetRK_RowStack
        Init 1 card per. Build top same rank. Play top. Drop full build
        sequence on foundation.

      _hint_ : pysollib.hint.AbstractHint
        .. pysollib.hint.defaultHint

    :note:
      ⟪autodrop⟫ disabled for non-events.
    """
    __info__ = dict(id=0x3aa02, name='Perpetual Motion', game_type=(
                    GT.PAIRING | GT.GNOME), decks=1, redeals=cs.INFINITE,
                    skill_level=SL.MOSTLY_LUCK, altnames=('First Law',),
                    version='3.20')
    __author__ = 'Markus Oberhumer'
    __version__ = 7.70

    _layout_ = AcesUpLayout.AcesUpLayout
    _talon_ = Wrap(TalonStack.DealGapRowRedealTalon, max_rounds=cs.INFINITE)
    _foundation_ = PerpetualMotion_Foundation
    _row_ = PerpetualMotion_RowStack

    def _create_game(self, **kw):
        """
        Create game format.

        Augment pile placements based on current form and group attributes.

        .. \_create_game(rows=4, playcards=12, texts=True, bases=[ANY])
             -> Layout
        """
        kwdefault(kw, rows=4, playcards=12, texts=True, bases=[cs.ANY])
        return super(PerpetualMotion, self)._create_game(**kw)

    def _start(self, **kw):
        """
        _start() -> None

        Deal 1 card per row.
        """
        self._play_sound('deal')
        self.s['talon'].dealRow()

    def _autopiles(self, event=None):
        """
        Return piles for auto or quick move.

        Overide to disable autodrop when not event.

        .. \_autopiles(self, event=None) -> seq(seq(Pile ...), seq(Pile ...),
             seq(Pile ...))
        """
        piles = super(PerpetualMotion, self)._autopiles(event)
        if event is None:
            return autostacks.auto_flip_quickplay(piles)
        return piles


class Simplex(PerpetualMotion):
    """
    Drop 1 deck by full same rank sequence on foundation using 9 top row,
    dealing all waste with no redeals.

    :CVariables:
      _layout_ : pysollib.layout.Layout
        .. pysollib.layouts.acesup.AcesUpLayout
        - row [9 horz N, vert offset]
        - talon [1 NW, no offset]
        - waste [1 E s.talon, no offset]
        - foundation [1 NE, no offset]

      _talon_ : pysollib.stack.Stack
        .. pysollib.stack.WasteTalon
        Deal 1 card per waste. No redeals.

      _waste_ : pysollib.stack.Stack
        .. pysollib.stack.WasteStack
        Init 1 card per. Build none. Play top.

      _foundation_ : pysollib.stack.Stack
        .. pysollib.stacks.pairing.SetRK_SingleFoundation

      _row_ : pysollib.stack.Stack
        .. pysollib.stacks.pairing.SetRK_RowStack
        Init 1 card per. Build top same rank. Play top. Drop full build
        sequence on foundation.

      _hint_ : pysollib.hint.AbstractHint
        .. pysollib.hint.defaultHint

    :note:
      ⟪autodrop⟫ disabled for non-events.
    """
    __info__ = dict(id=0x3ab34, name="Simplex", game_type=GT.PAIRING, decks=1,
                    skill_level=SL.MOSTLY_LUCK, version='0.91fc')
    __author__ = 'Skomoroh'
    __version__ = 7.70

    _talon_ = stack.WasteTalon
    _waste_ = stack.WasteStack

    def _create_game(self, **kw):
        """
        Create game format.

        Augment pile placements based on current form and group attributes.

        .. \_create_game(rows=9, playcards=12, texts=True, bases=(ANY,))
             -> Layout
        """
        kw.setdefault('rows', 9)
        return super(Simplex, self)._create_game(**kw)

    def _start(self, **kw):
        """
        _start() -> None

        Deal 1 card per row and 1 card per waste.
        """
        super(Simplex, self)._start(**kw)
        self.s['talon'].deal_cards()


class Deck(game.Game):
    """
    Drop 1 deck by same suit pair on foundation dealing all row.

    :CVariables:
      _layout_ : pysollib.layout.Layout
        .. pysollib.layouts.acesup.AcesUpLayout
        - row [4 horz N, vert offset]
        - talon [1 NW, no offset]
        - foundation [1 NE, no offset]

      _talon_ : pysollib.stack.Stack
        .. pysollib.stack.DealRowTalon
        Deal 1 card per row. No redeals.

      _foundation_ : pysollib.stack.Stack
        .. pysollib.stacks.pairing.PairSS_SingleFoundation

      _row_ : pysollib.stack.Stack
        .. pysollib.stacks.pairing.PairDropRowStack
        Init 1 card per. Build any top when gap. Play top. Drop same suit pair
        on foundation.

      _hint_ : pysollib.hint.AbstractHint
        .. pysollib.hint.defaultHint

    :note:
      ⟪autodrop⟫ disabled for non-events.
    """
    __info__ = dict(id=0x3ac2c, name='Deck', game_type=GT.PAIRING, decks=1,
                    skill_level=SL.LUCK, version='1.00fc')
    __author__ = 'Skomoroh'
    __version__ = 7.70

    _layout_ = AcesUpLayout.AcesUpLayout
    _talon_ = stack.DealRowTalon
    _foundation_ = PairingStack.PairSS_SingleFoundation
    _row_ = PairingStack.PairDropRowStack

    def _create_game(self, **kw):
        """
        Create game format.

        Augment pile placements based on current form and group attributes.

        .. \_create_game(rows=4, playcards=12, text=True, bases=[ANY]) -> Layout
        """
        kwdefault(kw, rows=4, playcards=12, texts=True, bases=[cs.ANY])
        return super(Deck, self)._create_game(**kw)

    def _start(self, **kw):
        """
        _start() -> None

        Deal 1 card per row.
        """
        self._play_sound('deal')
        self.s['talon'].dealRow()

    def _autopiles(self, event=None):
        """
        Return piles for auto or quick move.

        Overide to disable autodrop when not event.

        .. \_autopiles(self, event=None) -> seq(seq(Pile ...), seq(Pile ...),
             seq(Pile ...))
        """
        piles = super(Deck, self)._autopiles(event)
        if event is None:
            return autostacks.auto_flip_quickplay(piles)
        return piles


class Cover(Deck):
    """
    Drop 1 deck by same suit pair on foundation with gap deal 1 card from
    talon.

    :CVariables:
      _layout_ : pysollib.layout.Layout
        .. pysollib.layouts.acesup.AcesUpLayout
        - row [4 horz N, vert offset]
        - talon [1 NW, no offset]
        - foundation [1 NE, no offset]

      _talon_ : pysollib.stack.Stack
        .. pysollib.stack.Talon
        No redeals.

      _foundation_ : pysollib.stack.Stack
        .. pysollib.stacks.pairing.PairSS_SingleFoundation

      _row_ : pysollib.stack.Stack
        .. pysollib.stacks.pairing.PairDropRowStack
        Init 1 card per. Build any top when gap. Play top. Drop same suit pair
        on foundations. Gap top card from talon.

      _hint_ : pysollib.hint.AbstractHint
        .. pysollib.hint.defaultHint

    :note:
      ⟪autodrop⟫ disabled
    """
    __info__ = dict(id=0x3aba8, name='Cover', game_type=(GT.PAIRING |
                    GT.GNOME), decks=1, skill_level=SL.LUCK, version='0.93fc')
    __author__ = 'Skomoroh'
    __version__ = 7.70

    _talon_ = stack.Talon

    @state.move_state('fill')
    def _auto_fill(self, stack):
        """
        Any row gap fill 1 card from talon.

        *Parameters*:
          stack : stack.Stack
            pile that just had cards play.

        *Requires*:
          `pysollib.stackfill.fromTalon` for further details.
        """
        fill.fromTalon(self, stack, self.s['rows'])


class Manx(game.Game):
    """
    Drop 1 deck by full rank sequence on foundation with 1 top reserve.

    :CVariables:
      _layout_ : pysollib.layout.Layout
        .. pysollib.layouts.acesup.AcesUpLayout
        - row [4 horz N, vert offset]
        - talon [1 NE, no offset]
        - reserve [1 S s.talon, no offset]
        - foundation [4 vert NW, no offset]

      _talon_ : pysollib.stack.Stack
        .. pysollib.stack.DealRowTalon
        Deal 1 card per row. No redeals.

      _foundation_ : pysollib.stack.Stack
        .. pysollib.stacks.spider.RK_Foundation
        Build full sequence down in rank alone. Play none.

      _row_ : stack.Stack
        .. pysollib.stacks.spider.Drop_RK_RowStack (mod=13)
        Init 1 card per. Build down in rank alone wrap. Play sequence. Drop
        full build sequence on foundation.

      _reserve_ : pysollib.stack.Stack
        .. pysollib.stack.Reserve
        Build any top. Play top. Max 1 card.

      _hint_ : pysollib.hint.AbstractHint
        .. pysollib.hint.defaultHint
    """
    __info__ = dict(id=0x3ac75, name='Manx', game_type=GT.SPIDER, decks=1,
                    skill_level=SL.MOSTLY_SKILL, version='1.10fc')
    __author__ = 'Skomoroh'
    __version__ = 7.70

    _layout_ = AcesUpLayout.AcesUpLayout
    _talon_ = stack.DealRowTalon
    _foundation_ = SpiderStack.RK_Foundation
    _row_ = Wrap(SpiderStack.DropRK_RowStack, mod=13)
    _reserve_ = stack.ReserveStack

    def _create_game(self, **kw):
        """
        Create game format.

        Augment pile placements based on current form and group attributes.

        .. \_create_game(rows=4, playcards=20, reserves=1) -> Layout
        """
        kwdefault(kw, rows=4, playcards=20, reserves=1)
        return super(TabbyCat, self)._create_game(**kw)

    def _start(self, **kw):
        """
        _start() -> None

        Deal 1 card per row.
        """
        self._play_sound('deal')
        self.s['talon'].dealRow()


class TabbyCat(Manx):
    """
    Drop 1 deck by full rank sequence on foundation with 1 sequence reserve.

    :CVariables:
      _layout_ : pysollib.layout.Layout
        .. pysollib.layouts.acesup.AcesUpLayout
        - row [4 horz N, vert offset]
        - talon [1 NE, no offset]
        - reserve [1 S s.talon, no offset]
        - foundation [4 vert NW, no offset]

      _talon_ : pysollib.stack.Stack
        .. pysollib.stack.DealRowTalon
        Deal 1 card per row. No redeals.

      _foundation_ : pysollib.stack.Stack
        .. pysollib.stacks.spider.RK_Foundation
        Build full sequence down in rank alone. Play none.

      _row_ : stack.Stack
        .. pysollib.stacks.spider.Drop_RK_RowStack (mod=13)
        Init 1 card per. Build down in rank alone wrap. Play sequence. Drop
        full build sequence on foundation.

      _reserve_ : pysollib.stack.Stack
        .. pysollib.stacks.freecell.SequenceReserve

        Build any row sequence. Play row sequence.

      _hint_: pysollib.hint.AbstractHint
        .. pysollib.hint.defaultHint
    """
    __info__ = dict(id=0x3ac74, name='Tabby Cat', game_type=GT.SPIDER,
                    decks=1, skill_level=SL.MOSTLY_SKILL,
                    version='1.10fc')
    __author__ = 'Skomoroh'
    __version__ = 7.70

    _reserve_ = FreeCellStack.SequenceReserve

    def _create_game(self, **kw):
        """
        Create game format.

        Augment pile placements based on current form and group attributes.

        .. \_create_game(rows=4, playcards=20, reserves=1, holdcards=12)
             -> Layout
        """
        kw.setdefault('holdcards', 12)
        return super(TabbyCat, self)._create_game(**kw)


class MaineCoon(TabbyCat):
    """
    Drop 2 deck by full rank sequence on foundation with 1 sequence reserve.

    :CVariables:
       _layout_ : pysollib.layout.Layout
         .. pysollib.layouts.acesup.AcesUpLayout
         - row [4 horz N, vert offset]
         - talon [1 NE, no offset]
         - reserve [1 S s.talon, no offset]
         - foundation [8 over 2 col NW, no offset]

       _talon_ : pysollib.stack.Stack
         .. pysollib.stack.DealRowTalon
         Deal 1 card per row. No redeals.

       _foundation_ : stack.Stack
         .. spider.RK_Foundation
         Build full sequence down in rank alone. Play none.

       _row_ : pysollib.stack.Stack
         .. pysollib.stacks.spider.Drop_RK_RowStack (mod=13)
         Init 1 card per. Build down in rank alone wrap. Play sequence. Drop
         full build sequence on foundation.

       _reserve_ : pysollib.stack.Stack
         .. pysollib.stacks.freecell.SequenceReserve
         Build any seq. Play seq.

       _hint_ : pysollib.hint.AbstractHint
         .. pysollib.hint.defaultHint
    """
    __info__ = dict(id=0x3ac76, name='Maine Coon', game_type=GT.SPIDER,
                    decks=2, skill_level=SL.MOSTLY_SKILL, version='1.10fc')
    __author__ = 'Skomoroh'
    __version__ = 7.70

    def _create_game(self, **kw):
        """
        Create game format.

        Augment pile placements based on current form and group attributes.

        .. \_create_game(rows=4, playcards=26, reserves=1, holdcards=12)
             -> Layout
        """
        kw.setdefault('playcards', 26)
        return super(MaineCoon, self)._create_game(**kw)


PROVIDES = [AcesUp, Fortunes, RussianAces, PerpetualMotion, AcesUp5, Cover,
            Deck, FiringSquad, TabbyCat, Manx, MaineCoon, Simplex]